import sys
import re
import logging
import sysutils
import time

#all possible host values
validHosts = ["anl-mempt-1", "anl-mempt-2", "anl-mempt-3", "nersc-diskpt-1", "nersc-diskpt-2", "nersc-diskpt-3"]
#known image names by project
validImages = {}
validImages["climate100"] = ["climate100.anl-mempt-1.a", "climate100.anl-mempt-2.a", "climate100.anl-mempt-3.a", "climate100.nersc-diskpt-1.a", "climate100.nersc-diskpt-2.a", "climate100.nersc-diskpt-3.a"]
validImages["fnal"] = ["fnal.anl-mempt-1.a", "fnal.anl-mempt-2.a", "fnal.anl-mempt-3.a", "fnal.nersc-diskpt-1.a", "fnal.nersc-diskpt-2.a", "fnal.nersc-diskpt-3.a"]
validImages["glenn"] = ["glenn.anl-mempt-2.a", "glenn.nersc-diskpt-2.ai"]
validImages["hntes"] = ["hntes.anl-mempt-1.a","hntes.anl-mempt-2.a","hntes.anl-mempt-3.a","hntes.nersc-diskpt-1.a","hntes.nersc-diskpt-2.a","hntes.nersc-diskpt-3.a"]
validImages["sdci"] = ["sdci.anl-mempt-1.a","sdci.anl-mempt-2.a","sdci.anl-mempt-3.a","sdci.nersc-diskpt-1.a","sdci.nersc-diskpt-2.a","sdci.nersc-diskpt-3.a"]
validImages["rich"] = ["rich.anl-mempt-1.a","rich.anl-mempt-2.a","rich.anl-mempt-3.a","rich.nersc-diskpt-1.a","rich.nersc-diskpt-2.a","rich.nersc-diskpt-3.a"]
validImages["suny"] = ["suny.anl-mempt-1.a","suny.anl-mempt-2.a","suny.anl-mempt-3.a","suny.nersc-diskpt-1.a","suny.nersc-diskpt-2.a","suny.nersc-diskpt-3.a"]
validImages["ezra"] = ["ezra.anl-mempt-1.a","ezra.anl-mempt-2.a","ezra.anl-mempt-3.a","ezra.nersc-diskpt-1.a","ezra.nersc-diskpt-2.a","ezra.nersc-diskpt-3.a"]


#Class to store data relevant for verification of events.
#Data needs to be parsed from the DESCRIPTION section of an event.
class Reservation:

	def __init__(self):
		self.name = ""
		self.project = ""
		self.host = ""
		self.image = ""
		self.network = ""
		#Date strings using format in system file: HH:MM.mm/dd/yy
		self.startDate = ""
		self.endDate = ""

	#The startDate in seconds since epoch, optionally offset
	def get_start_float(self, offset=0):
		time.mktime(time.strptime(self.startDate, "%H:%M.%m/%d/%y")) + offset

	#The endDate in seconds since epoch, optionally offset
	def get_end_float(self, offset=0):
		time.mktime(time.strptime(self.endDate, "%H:%M.%m/%d/%y")) + offset

	def __repr__(self):
		return "Start=" + self.startDate + ", End=" + self.endDate + ", Host=" + self.host + ", Image=" + self.image 

	def __eq__(self, tgt):
		#if not self.host == tgt.host:
		#	print "Reservation host not eq: " + self.host + " -- " + tgt.host
		#if not self.image == tgt.image:
		#	print "image not eq: " + self.image + " -- " + tgt.image
		#if not self.startDate == tgt.startDate:
		#	print "startDate not eq: " 
		if (self.host == tgt.host) and (self.image == tgt.image) and (self.startDate == tgt.startDate) and (self.endDate == tgt.endDate):
			return True
		else:
			return False

def err_action(msg):
	print msg
	logging.error(msg) 
	return (None,msg)

#Parameter is an EventData or RecurringEvent obj and info is extracted from the description.
#The description is expected to be field=value pairs separated by semicolon, 
#and multi-element values are separated by a colon.
#Returns a list of one or more Reservation objs, and err string
def gCalReservation(eventInst):
	fields = {}
	errmsg = None
	#create standard error message for use in various types of error
	if not eventInst.summary:
		errmsg =  "FORMATTING ERROR for gCal event: no summary or description"
	else:
		errmsg =  "FORMATTING ERROR for gCal event: " + eventInst.summary
	errmsg = errmsg + "\nReservation start: " + eventInst.getStartDateLocal().strftime("%H:%M.%m/%d/%y") + "\nReservation end: " + eventInst.getEndDateLocal().strftime("%H:%M.%m/%d/%y")
	if not eventInst.description:
		errmsg = errmsg + "\nEvent had no description value"
		return err_action(errmsg)

	descInfo = eventInst.description.split(':',1)[1]
	hosts = None
	name = None
	project = None
	network = None
	for f in descInfo.split(';'):
		fv = f.split('=', 1)
		if len(fv) > 1:
			fields[fv[0].lstrip('\\n').rstrip('\\n').lstrip().rstrip().lower()] = fv[1].lstrip('\\n').rstrip('\\n').lstrip().rstrip()
	if not fields:
		errmsg = errmsg + "\nNo fields were found in the event description"
		return err_action(errmsg)
	if "name" in fields:
		name = fields["name"]
	if "project" in fields:
		project = fields["project"]
	if "network" in fields:
		network = fields["network"]
	if "host" in fields:
		if fields["host"].startswith("all"):
			#get image info
			allinfo = fields["host"].split(':',1)
			if len(allinfo) > 1:
				hosts = zip(validHosts, validImages[allinfo[1]])
			else:
				errmsg = errmsg + "\nNo image name provided for 'all hosts'"
				return err_action(errmsg)
		else:
			#break up list of values
			hosts = [h.split(':') for h in fields["host"].split(',')]
			#convert to list of tuples - ignoring data not in host:image format
			hosts = [(h[0].rstrip('\\').lstrip().rstrip(), h[1].rstrip('\\').lstrip().rstrip()) for h in hosts if len(h) > 1]
			#print info on invalid names
			for (h,img) in hosts:
				if not h in validHosts:
					print "The host name requested is not a valid host: " + h
					logging.info("The host name requested is not a valid host: " + h)
				if project and project in validImages:
					if not img in validImages[project]:
						print "The image " + img + " requested is not valid for project " + project
						logging.info("The image " + img + " requested is not valid for project " + project)
			#take out invalid hosts
			hosts = [(h,img) for (h,img) in hosts if h in validHosts]
	else:
		errmsg = errmsg + "\nThe host field was not found in the description"
		return err_action(errmsg)
	res = []
	if hosts:
		#create a reservation for each host
		for (h, img) in hosts:
			entry = Reservation()
			entry.host = h
			entry.image = img
			entry.startDate = eventInst.getStartDateLocal().strftime("%H:%M.%m/%d/%y")
			entry.endDate = eventInst.getEndDateLocal().strftime("%H:%M.%m/%d/%y")
			res.append(entry)
	return (res, None)


#Read a text file on local machine that contains info on what machine configurations
#are scheduled to be used.
#SCRIPTNAME = "/usr/local/cfw/scripts/admin_interface/set_diskpt_image.py"
SYSFILE = '/usr/local/cfw/scripts/reservation_system/reservations'
def sysReservation(filename=SYSFILE):
	data = None
	try:
		f = open(filename)
		data = f.read()
		f.close()
	except IOError:
		print "Error reading reservation system task file: " + filename
		sys.exit()
	resInfo = [line.split()[1:] for line in data.splitlines() if line.lstrip().lstrip('"').startswith('host')]	
	res = []
	for fields in resInfo:
		entry = Reservation()
		entry.host = fields[0].rstrip('"').lstrip('"').lstrip().rstrip()
		entry.image = fields[1].rstrip('"').lstrip('"').lstrip().rstrip()
		entry.startDate = fields[2].lstrip().rstrip()
		entry.endDate = fields[3].lstrip().rstrip()
		res.append(entry)
	return res


def create_description(hostimage, project=None, name=None):
	desc = "host="
	for (host,image) in hostimage:
		desc = desc + host + " : " + image + " , "
	desc = desc.rstrip(',')
	if project:
		desc = desc + "; project=" + project
	if name:
		desc = desc + "; name=" + name
